Naučte sa implementovať React Error Boundaries s hooks na zvládanie chýb pri načítavaní zdrojov a zlepšenie používateľského zážitku a stability aplikácie.
Robustné načítavanie zdrojov v Reacte: Zvládnutie Error Boundaries pomocou Hooks
V moderných webových aplikáciách je asynchrónne načítavanie zdrojov bežnou praxou. Či už ide o získavanie dát z API, načítavanie obrázkov alebo importovanie modulov, zvládanie potenciálnych chýb počas načítavania zdrojov je kľúčové pre plynulý používateľský zážitok. React Error Boundaries poskytujú mechanizmus na zachytávanie chýb JavaScriptu kdekoľvek v strome ich podradených komponentov, zaznamenávanie týchto chýb a zobrazenie záložného UI namiesto pádu celej aplikácie. Tento článok skúma, ako efektívne používať Error Boundaries v spojení s React Hooks na správu chýb pri načítavaní zdrojov.
Pochopenie Error Boundaries
Pred Reactom 16 neriešené chyby JavaScriptu počas vykresľovania komponentov mohli poškodiť interný stav Reactu a spôsobiť záhadné chyby pri nasledujúcich vykresleniach. Error Boundaries tento problém riešia tým, že fungujú ako bloky na zachytávanie všetkých chýb, ktoré sa vyskytnú v ich podradených komponentoch. Sú to React komponenty, ktoré implementujú jednu alebo obe z nasledujúcich metód životného cyklu:
static getDerivedStateFromError(error): Táto statická metóda sa volá po tom, čo potomok komponentu vyhodí chybu. Prijíma vyhodenú chybu ako argument a vracia hodnotu na aktualizáciu stavu komponentu.componentDidCatch(error, info): Táto metóda životného cyklu sa volá po tom, čo potomok komponentu vyhodí chybu. Prijíma vyhodenú chybu ako argument, ako aj objekt obsahujúci informácie o tom, ktorý komponent chybu vyhodil. Môžete ju použiť na zaznamenanie informácií o chybe.
Dôležité je, že Error Boundaries zachytávajú chyby iba vo fáze vykresľovania, v metódach životného cyklu a v konštruktoroch celého stromu pod nimi. Nezachytávajú chyby v:
- Obsluhe udalostí (viac sa dozviete v sekcii nižšie)
- Asynchrónnom kóde (napr. callbacky
setTimeoutaleborequestAnimationFrame) - Vykresľovaní na strane servera (Server-side rendering)
- Chybách vyhodených v samotnej Error Boundary (namiesto jej potomkov)
Error Boundaries a React Hooks: Silná kombinácia
Zatiaľ čo na implementáciu Error Boundaries sa tradične používali triedne komponenty, React Hooks ponúkajú stručnejší a funkcionálnejší prístup. Môžeme vytvoriť opakovane použiteľný hook useErrorBoundary, ktorý zapuzdrí logiku spracovania chýb a poskytuje pohodlný spôsob, ako obaliť komponenty, ktoré môžu počas načítavania zdrojov vyhadzovať chyby.
Vytvorenie vlastného hooku useErrorBoundary
Tu je príklad hooku useErrorBoundary:
import { useState, useCallback } from 'react';
function useErrorBoundary() {
const [error, setError] = useState(null);
const resetError = useCallback(() => {
setError(null);
}, []);
const captureError = useCallback((e) => {
setError(e);
}, []);
const ErrorBoundary = useCallback(({ children, fallback }) => {
if (error) {
return fallback ? fallback : An error occurred: {error.message || String(error)};
}
return children;
}, [error]);
return { ErrorBoundary, captureError, error, resetError };
}
export default useErrorBoundary;
Vysvetlenie:
useState: PoužívameuseStatena správu stavu chyby. Na začiatku nastaví chybu nanull.useCallback: PoužívameuseCallbackna memoizáciu funkciíresetErroracaptureError. Je to dobrá prax, aby sa predišlo zbytočným opätovným vykresleniam, ak sa tieto funkcie odovzdávajú ako props.- Komponent
ErrorBoundary: Toto je funkcionálny komponent vytvorený pomocouuseCallback, ktorý prijímachildrena voliteľný propfallback. Ak v stave existuje chyba, vykreslí buď poskytnutýfallbackkomponent, alebo predvolenú chybovú správu. V opačnom prípade vykreslí deti. Toto funguje ako naša Error Boundary. Pole závislostí `[error]` zabezpečuje, že sa opätovne vykreslí, keď sa zmení stav `error`. - Funkcia
captureError: Táto funkcia sa používa na nastavenie stavu chyby. Budete ju volať v rámci blokutry...catchpri načítavaní zdrojov. - Funkcia
resetError: Táto funkcia vymaže stav chyby, čo umožní komponentu opätovne vykresliť svoje deti (a potenciálne sa znova pokúsiť načítať zdroj).
Implementácia načítavania zdrojov so spracovaním chýb
Teraz sa pozrime, ako použiť tento hook na spracovanie chýb pri načítavaní zdrojov. Zvážte komponent, ktorý získava údaje o používateľovi z API:
import React, { useState, useEffect } from 'react';
import useErrorBoundary from './useErrorBoundary';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const { ErrorBoundary, captureError, error, resetError } = useErrorBoundary();
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setUser(data);
} catch (e) {
captureError(e);
}
};
fetchData();
}, [userId, captureError]);
if (error) {
return (
Failed to load user data. {user.name}
Email: {user.email}
{/* Other user details */}Vysvetlenie:
- Importujeme hook
useErrorBoundary. - Voláme hook, aby sme získali komponent
ErrorBoundary, funkciucaptureError, staverrora funkciuresetError. - Vnútri hooku
useEffectobalíme volanie API do blokutry...catch. - Ak sa počas volania API vyskytne chyba, zavoláme
captureError(e), aby sme nastavili stav chyby. - Ak je stav
errornastavený, vykreslíme komponentErrorBoundary. Poskytujeme vlastný propfallback, ktorý zobrazí chybovú správu a tlačidlo „Skúsiť znova“. Kliknutím na tlačidlo sa zavoláresetError, aby sa vymazal stav chyby, čo spustí opätovné vykreslenie a ďalší pokus o načítanie dát. - Ak sa nevyskytla žiadna chyba a údaje o používateľovi sú načítané, vykreslíme detaily profilu používateľa.
Spracovanie rôznych typov chýb pri načítavaní zdrojov
Rôzne typy chýb pri načítavaní zdrojov môžu vyžadovať rôzne stratégie spracovania. Tu sú niektoré bežné scenáre a ako ich riešiť:
Sieťové chyby
Sieťové chyby sa vyskytujú, keď sa klient nemôže pripojiť k serveru (napr. z dôvodu výpadku siete alebo nedostupnosti servera). Vyššie uvedený príklad už zvláda základné sieťové chyby pomocou `response.ok`. Možno budete chcieť pridať sofistikovanejšiu detekciu chýb, napríklad:
//Inside the fetchData function
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
// Consider adding specific error code handling
if (response.status === 404) {
throw new Error("User not found");
} else if (response.status >= 500) {
throw new Error("Server error. Please try again later.");
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
}
const data = await response.json();
setUser(data);
} catch (error) {
if (error.message === 'Failed to fetch') {
// Likely a network error
captureError(new Error('Network error. Please check your internet connection.'));
} else {
captureError(error);
}
}
V tomto prípade môžete používateľovi zobraziť správu, ktorá naznačuje, že nastal problém so sieťovým pripojením, a navrhnúť mu, aby skontroloval svoje internetové pripojenie.
Chyby API
Chyby API sa vyskytujú, keď server vráti chybovú odpoveď (napr. 400 Bad Request alebo 500 Internal Server Error). Ako je uvedené vyššie, môžete skontrolovať `response.status` a tieto chyby primerane spracovať.
Chyby pri parsovaní dát
Chyby pri parsovaní dát sa vyskytujú, keď odpoveď zo servera nie je v očakávanom formáte a nedá sa spracovať (napr. neplatný JSON). Tieto chyby môžete spracovať obalením volania response.json() do bloku try...catch:
//Inside the fetchData function
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setUser(data);
} catch (error) {
if (error instanceof SyntaxError) {
captureError(new Error('Failed to parse data from server.'));
} else {
captureError(error);
}
}
Chyby pri načítavaní obrázkov
Pri načítavaní obrázkov môžete použiť obsluhu udalosti onError na značke <img>:
function MyImage({ src, alt }) {
const { ErrorBoundary, captureError } = useErrorBoundary();
const [imageLoaded, setImageLoaded] = useState(false);
const handleImageLoad = () => {
setImageLoaded(true);
};
const handleImageError = (e) => {
captureError(new Error(`Failed to load image: ${src}`));
};
return (
Failed to load image.